import { PublishBase } from "./PublishBase";
import { paserIndexJs } from "./PaserHtmlUtil";
import { join, basename } from "path";
import { cpFile, delDir, createDirSync, createManifest } from "../utils/FileUtil";
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
import { downloadFileAsync } from "../http/LoadFile.";
import { compactMd5Json } from "../utils/JsonUtil";

export abstract class PublishLaya2Base extends PublishBase {
    abstract get libJs(): string;
    async buildProject() {
        this.log('开始打包游戏, 请稍等');
        let crtProjPath = this.mProjPath;

        // 解index.js文件
        let htmlObj = paserIndexJs(this._publishVo.fromPath);
        this.log('开始修改config.js');
        // 写入config
        this.mWriteConfig();
        cpFile(join(this._publishVo.fromPath, "index.js"), join(crtProjPath, "index.js"));
        if (this.libJs) {
            if (!existsSync(join(this._publishVo.fromPath, "libs/" + this.libJs))) {
                this.log(`库文件${this.libJs}不存在`);
            }
            htmlObj.js.push("libs/" + this.libJs);
        }

        await this.loadJsLibs(htmlObj.loadJs, crtProjPath, htmlObj.loadJsReplaceList);

        this.log('开始合并js代码');
        await this.compressJs(htmlObj.js, this._publishVo.fromPath, crtProjPath);
        this.log('开始hash素材');
        if (!this._checkRes) {
            this.log('素材不需要重新生成');
            return;
        }
        let resPath: string;
        if (this._publishVo.localRes) {
            resPath = this.mProjPath;
        } else {
            resPath = join(this._publishVo.toPath, this._version);
            if (existsSync(resPath)) {
                delDir(resPath);
            }
        }
        let versionInfo = await this.cpRes(resPath);

        if (this._publishVo.compressImg) {
            let excludeHash: any;
            if (this.mProjectInfo.excludeCompress) {
                excludeHash = {};
                let excludeList = this.mProjectInfo.excludeCompress;
                for (let i = 0; i < excludeList.length; i++) {
                    let realFileName = versionInfo[excludeList[i].replace(/\\/g, "\/")] || excludeList[i];
                    let excludePath = join(resPath, realFileName);
                    excludeHash[excludePath] = 1;
                }
            }
            await this.compressImg(resPath, excludeHash);
        }
    }

    protected async loadJsLibs(jsLibs: string[], outPath: string, loadJsReplaceList: string[]) {
        if (jsLibs && jsLibs.length > 0) {
            createDirSync(join(outPath, "loadLibs"));
            let filePath = join(this.mProjPath, "index.js");
            if (!existsSync(filePath)) {
                return;
            }
            let fileContent = readFileSync(filePath, "utf8");
            for (let i = 0; i < jsLibs.length; i++) {
                let fullFileUri = jsLibs[i];
                let minUri = fullFileUri;
                if (fullFileUri.lastIndexOf(".min.js") == -1) {
                    let arr = fullFileUri.split(".");
                    let fileType = arr.pop();
                    minUri = arr.join(".") + ".min." + fileType;
                }
                let fileName = "";
                try {
                    fileName = basename(minUri);
                    await downloadFileAsync(minUri + "?t=" + Date.now(), join(outPath, "loadLibs", fileName));
                } catch (e) {
                    fileName = basename(fullFileUri);
                    await downloadFileAsync(fullFileUri + "?t=" + Date.now(), join(outPath, "loadLibs", fileName));
                }
                // let rex = new RegExp(loadJsReplaceList[i], "g");
                fileContent = fileContent.replace(loadJsReplaceList[i], "\"loadLibs/" + fileName + "\"");
            }
            writeFileSync(filePath, fileContent, "utf8");
        }
    }

    protected mWriteConfig() {
        writeFileSync(join(this.mProjPath, this.getConfigName()), "var config = " + this.config + ";module.exports = config;");
    }

    async cpRes(resPath: string) {
        if (!existsSync(resPath)) {
            mkdirSync(resPath);
        }
        // 拷贝素材
        await this.copyDir(join(this._publishVo.fromPath, 'res'), join(resPath, 'res'), !this._publishVo.localRes, { dir: ['\W+\.svn'] });
        let info = await this.createVersion(resPath);
        if (info === null) {
            console.log(`素材manifest: res_${this._version}.json 生成出错`);
            return;
        }
        if (!this._publishVo.localRes) {
            info = compactMd5Json(info);
            writeFileSync(join(resPath, `res_${this._version}.json`), JSON.stringify(info));
        }
        this.log('素材拷贝完毕');
        return info;
    }

    async createVersion(resPath: string) {
        return new Promise((resolve, reject) => {
            createManifest(resPath, (info: any) => {
                resolve(info);
            })
        })
    }

    getConfigName() {
        return "config.js";
    }
}